package cool.mtc.minghe.service.service.sys.org.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cool.mtc.core.exception.ServiceException;
import cool.mtc.core.page.PageData;
import cool.mtc.core.util.CollectionUtil;
import cool.mtc.minghe.data.entity.sys.org.OrgDO;
import cool.mtc.minghe.data.model.sys.org.dto.OrgDTO;
import cool.mtc.minghe.data.model.sys.org.dto.OrgDictDTO;
import cool.mtc.minghe.data.model.sys.org.dto.OrgListDTO;
import cool.mtc.minghe.data.model.sys.org.dto.OrgTreeSupport;
import cool.mtc.minghe.data.model.sys.org.form.OrgForm;
import cool.mtc.minghe.data.model.sys.org.query.OrgQuery;
import cool.mtc.minghe.service.mapper.sys.org.OrgMapper;
import cool.mtc.minghe.service.service.sys.org.OrgService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.stream.Collectors;

/**
 * @author 明河
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrgServiceImpl extends cool.mtc.minghe.service.service.BaseServiceImpl implements OrgService {
    private final OrgMapper orgMapper;

    @Override
    @Transactional
    public long insert(OrgForm form) {
        OrgDO orgDO = form.transToDO();
        if (null != form.getOrgParentId()) {
            OrgDO parentOrgDO = orgMapper.selectById(form.getOrgParentId());
            if (null == parentOrgDO) {
                throw new ServiceException("org.parent.non_exist");
            }
            orgDO.setParentId(parentOrgDO.getId());
            orgDO.setLevel(parentOrgDO.getLevel() + 1);
        }
        orgDO.setCreator(userId());
        orgMapper.insert(orgDO);
        return orgDO.getId();
    }

    @Override
    @Transactional
    public void update(OrgForm form) {
        OrgDO orgDO = orgMapper.selectById(form.getId());
        if (null == orgDO) {
            throw new ServiceException("org.data.expired");
        }
        form.updateDO(orgDO);
        orgMapper.updateById(orgDO);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        if (null == id) {
            return;
        }
        OrgDO orgDO = orgMapper.selectById(id);
        if (null == orgDO) {
            return;
        }
        this.handleCheckCanDelete(orgDO);
        orgMapper.deleteById(id);
    }

    /**
     * 检查是否可以删除
     */
    private void handleCheckCanDelete(OrgDO orgDO) {
        if (Boolean.TRUE.equals(orgDO.getPreset())) {
            throw new ServiceException("preset.delete.not_allow");
        }
        QueryWrapper<OrgDO> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", orgDO.getId());
        long childCount = orgMapper.selectCount(wrapper);
        if (0 == childCount) {
            return;
        }
        throw new ServiceException("当前数据已存在下级菜单，无法删除！(i18n)");
    }

    @Override
    public List<OrgListDTO> list(OrgQuery query) {
        List<OrgListDTO> list = orgMapper.list(query);
        return this.buildOrgTree(list);
    }

    @Override
    public PageData<OrgListDTO> pageList(OrgQuery query) {
        return null;
    }

    @Override
    public OrgDTO info(Long id) {
        if (null == id) {
            return null;
        }
        return orgMapper.getById(id);
    }

    @Override
    public List<OrgDictDTO> listDictTree() {
        List<OrgDictDTO> list = orgMapper.listDict();
        return this.buildOrgTree(list);
    }

    /**
     * 构建树结构
     */
    private <T extends OrgTreeSupport> List<T> buildOrgTree(List<T> list) {
        int level = this.getMaxLevel(list);
        return this.buildOrgTree(list, new ArrayList<>(), level);
    }

    /**
     * 从列表中取出level最大值，用以构建树结构
     */
    private <T extends OrgTreeSupport> int getMaxLevel(List<T> list) {
        OptionalInt optionalInt = list.stream().mapToInt(OrgTreeSupport::getLevel).max();
        return optionalInt.isPresent() ? optionalInt.getAsInt() : 0;
    }

    /**
     * 构建树结构
     */
    private <T extends OrgTreeSupport> List<T> buildOrgTree(List<T> allList, List<T> childList, int level) {
        List<T> parentList = allList.stream().filter(item -> item.getLevel() == level).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(parentList)) {
            return childList;
        }
        parentList.forEach(parent ->
                childList.forEach(child -> {
                    if (parent.getOrgId().equals(child.getOrgParentId())) {
                        parent.getChildren().add(child);
                    }
                })
        );
        return this.buildOrgTree(allList, parentList, level - 1);
    }
}
